/**
 *  \file I3OverlayNetwork.cpp
 *  \brief This class defines the functions of the i3 overlay network.
 *  The I3OverlayNetwork class implements the i3 specific functionality 
 *  in addition to the functionality derived from OCD.
 */

#include <assert.h>

#include "i3_debug.h"
#include "OCD_include.h"

#include "I3Functor.h"
#include "I3AddressBook.h"
#include "I3Id.h"
#include "I3Key.h"
#include "I3ConfigFile.h"
#include "I3TriggerConfigFile.h"
#include "PublicTrigger.h"
#include "I3OCDStateInfo.h"
#include "I3Params.h"
#include "I3Packet.h"
#include "I3TimerEvent.h"
#include "I3Trigger.h"
#include "I3OverlayNetwork.h"
#include "I3ClientContext.h"

#ifndef _WIN32
	#include <sys/socket.h>
	#include <arpa/inet.h>
	#include <netinet/in.h>
#endif

#include <errno.h>
#include <string.h>
#include <pthread.h>

#include <string>


extern "C" {
    #include "i3.h"
    #include "i3_api.h"
    #include "i3_id.h"
    #include "i3_addr.h"
    #include "i3_trigger.h"
    #include "i3_client_api.h"
}

#include "i3CommonHeaders.h"


void dummy_insertedTrigger(cl_trigger*, void*, void*);
void dummy_triggerNotFound(void *ctx_data, void *data, void* fun_ctx);
void dummy_constraint_failed(cl_trigger*, void*, void*);
void dummy_receive_packet(cl_trigger*, void*, void*);
void dummy_trigger_refresh_failed(cl_trigger*, void*, void*);

using namespace std;


extern "C" void proxy_trigger_inserted();


/**
  * Function definitions of the I3OverlayNetwork.
  */

/**
  * Constructor.
  * @param type         The type of the overlay network. For eg: I3
  * @param id           The id of the overlay network. For eg: I3.PlanetLab
  * @param desc         A brief description of the overlay.
  * @param fileName     The name of the overlay specific configuration
  * file
  * @param urlSuffixes  The string of space separated suffixes of URLs to be
  * handled by this overlay network.
  * @param handleLegacyURLs Should this overlay handle legacy URLs like 
  * www.abc.com?
  */
I3OverlayNetwork::I3OverlayNetwork(
        string type, string id, string desc, 
        string fileName, 
        string urlSuffixes, bool handleLegacyURLs
    ) :OCD(    type, id, desc, fileName, 
                urlSuffixes, handleLegacyURLs
            ) {

#ifdef _WIN32
		updateStatusTimer = NULL;
#endif
  
}

/**
  * Construct a new I3OverlayNetwork with fields taken from the
  * specified overlay network.
  */
I3OverlayNetwork::I3OverlayNetwork(OCD* o): OCD() {

    this->type = o->type;
    this->id = o->id;
    this->description = o->description;
    this->configFileName = o->configFileName;
    this->urlSuffixes = o->urlSuffixes;
    this->handleLegacyURLs = o->handleLegacyURLs;

    this->configPropertyMap = o->configPropertyMap;
    this->myNameList = o->myNameList;

#ifdef _WIN32
	this->updateStatusTimer = NULL;
#endif

}


#ifdef _WIN32
/**
 * Returns the windows registry key under which status information is stored.
 * This function is windows specific.
 * This function simply returns the id.  May be overloaded for specific overlays.
 */
const char* I3OverlayNetwork::getWinRegistryKey() {
    return "I3_Status"; 
}       
#endif


/** Adds a timer to event check if the proxy's IP address has changed.
  * Adds only the next timer event.  The function called when the timer 
  * triggers is responsible for calling this function again.
  */
void I3OverlayNetwork::addAddressChangeCheckTimer() {
 
    I3_PRINT_DEBUG0(DEBUG_LEVEL_SUPER, "Adding address change check timer\n");
    
    //add a timer event to check if the proxy's IP address has changed.
    TObjectFunctor<I3OverlayNetwork> *addrChange = 
                        new TObjectFunctor<I3OverlayNetwork>(
                                        this, 
                                        &I3OverlayNetwork::addressChangeCheck
                                    );
    
    TimerEvent *addressChangeTimer = TimerEvent::create(
                                                        ADDR_CHECK_PERIOD, 
                                                        0, 
                                                        (TFunctor *)addrChange, 
                                                        "Address Change Check Timer",
                                                        true
                                                    );
    
    addTimerEvent(addressChangeTimer);

}

/** Adds a timer to event check to periodically update the list of i3 servers
  * known to the proxy.
  * Adds only the next timer event.  The function called when the timer 
  * triggers is responsible for calling this function again.
  */
void I3OverlayNetwork::addServerUpdateTimer() {
 
    I3_PRINT_DEBUG0(I3_DEBUG_LEVEL_VERBOSE, "Adding Server Update timer\n");
    
    //add a timer event to update the list of i3 servers known to the proxy.
    TObjectFunctor<I3OverlayNetwork> *serverUpdate = 
                        new TObjectFunctor<I3OverlayNetwork>(
                                                this, 
                                                &I3OverlayNetwork::i3ServerUpdate
                                            );
    
    TimerEvent *serverUpdateTimer = TimerEvent::create (
                                INITIAL_SERVER_UPDATE_DELAY, 
                                0, 
                                (TFunctor *)serverUpdate, 
                                "Server Update Timer",
                                true
                            );
    
    addTimerEvent(serverUpdateTimer);

}

/**
 * This function is periodically called to update the list of i3 servers known
 * to the proxy.
 */
void I3OverlayNetwork::i3ServerUpdate() {

    if ( ! proxy->get_stopProxyFlag()) {	

	I3_PRINT_DEBUG0(DEBUG_LEVEL_SUPER, "Updating I3 Server List\n");
	context->doServerUpdate();

    	//Schedule the next server update
    	TObjectFunctor<I3OverlayNetwork> *serverUpdate = 
                                new TObjectFunctor<I3OverlayNetwork>(
                                            this, 
                                            &I3OverlayNetwork::i3ServerUpdate
                                        );
    
    	TimerEvent *serverUpdateTimer = TimerEvent::create (
                                                SERVER_UPDATE_PERIOD, 
                                                0, 
                                                (TFunctor *)serverUpdate, 
                                                "Server Update Timer",
                                                true
                                            );
    
    	addTimerEvent(serverUpdateTimer);
    }
}
	
#ifdef _WIN32
/** Periodically update the status in the registry. 
 */
void I3OverlayNetwork::updateStatus() {

	// Update the status.
	if (context->isTCPSupported()) {
		if (!context->isTCPInitOk()) {
			setMonitor_CurrentStatusMsg (string ("TCP connection to i3 server NOT established."));
			setMonitor_CurrentIcon (string("i3_disconnect.ico"));

		} else {
			setMonitor_CurrentStatusMsg (string ("TCP connection to i3 server ESTABLISHED."));
			setMonitor_CurrentIcon (string("i3_run.ico"));

		}
	} else {
		// UDP being used
		// check the number of servers that have been found.
		char tmpMsgBuf[MAX_BUF_SIZE];
		snprintf (tmpMsgBuf, MAX_BUF_SIZE, "%d i3 servers currently known.", context->g_ctx->num_servers);
		setMonitor_CurrentStatusMsg (string (tmpMsgBuf));
		setMonitor_CurrentIcon (string("i3_run.ico"));

	}

	// Schedule the next updateStatus check
	scheduleUpdateStatus();

}

void I3OverlayNetwork::scheduleUpdateStatus() {

	if (! proxy->get_stopProxyFlag()) {
    
    	TObjectFunctor<I3OverlayNetwork> *tmpFunctor = new TObjectFunctor<I3OverlayNetwork>(this, &I3OverlayNetwork::updateStatus);
    	updateStatusTimer = TimerEvent::create (UPDATE_STATUS_PERIOD, 0, (TFunctor *)tmpFunctor, "Update Status Timer", true);
    	addTimerEvent(updateStatusTimer);
    }
}

#endif
	
/**
  * This function checks if the IP address of the proxy has changed.  
  * If yes, it updates the necessary state information.
  * The timer event for the next check is also added.
  */
void I3OverlayNetwork::addressChangeCheck() {

   
    // The following are just for display
    I3_PRINT_DEBUG0(DEBUG_LEVEL_VERBOSE, 
                    "\n#############################################################\n"
                    "\n\t\tChecking if Proxy's IP Address has changed.\n"
                    "\n#############################################################\n"
                );

    struct in_addr tmpCurrIP;

    bool addrOkFlag;
    tmpCurrIP.s_addr = htonl(proxy->getCurrentIP(&addrOkFlag).s_addr);
    if (context->g_ctx->local_ip_addr.s_addr != ntohl(tmpCurrIP.s_addr)) {
        struct in_addr temp;
	    temp.s_addr = htonl(context->g_ctx->local_ip_addr.s_addr);
	    I3_PRINT_DEBUG1(DEBUG_LEVEL_SUPER, 
			"Detected address change\nNew address %s\n", 
			inet_ntoa (tmpCurrIP));
        I3_PRINT_DEBUG1(DEBUG_LEVEL_SUPER, "Original address: %s\n", 
		    inet_ntoa(temp));

    } else {
        struct in_addr temp;
	temp.s_addr = htonl(context->g_ctx->local_ip_addr.s_addr);
	I3_PRINT_DEBUG1(DEBUG_LEVEL_VERBOSE, 
		    "Proxy Address has not changed, still: %s\n", 
		    inet_ntoa(temp));
    }
    
    // The actual check and change occurs through the following client API function
    if ( ! proxy->get_stopProxyFlag()) {
    	context->doAddressChangeCheck();
    }
 
    //Schedule the next address check event.
    
    if (! proxy->get_stopProxyFlag()) {
    
    	TObjectFunctor<I3OverlayNetwork> *addrChange = new TObjectFunctor<I3OverlayNetwork>(this, &I3OverlayNetwork::addressChangeCheck);
    	TimerEvent *addressChangeTimer = TimerEvent::create (ADDR_CHECK_PERIOD, 0, (TFunctor *)addrChange, "Address Change Check", true);
    	addTimerEvent(addressChangeTimer);
    }
}

/**
  * Initializes the I3 Overlay interface.  
  * A public trigger for this proxy is inserted in the i3
  * infrastructure.  The process is synchronous, i.e. the function will
  * return only after all initialization is complete.
  * @param proxy A pointer to the proxy of which this overlay is a part.
  * @param oci  The OCI associated with this OCD.
  */
void I3OverlayNetwork::init(Proxy *prxy, OCI* oci, bool recoverFromCrash) {

    I3_PRINT_DEBUG1(I3_DEBUG_LEVEL_MINIMAL, "Initializing I3 Overlay %s...\n", id.c_str());
    
    this->proxy = prxy;
    this->oci = oci;

    initConfigValues();

    context = new I3ClientContext(this, configFileName.c_str());
    internalState = I3_INIT_IN_PROGRESS;

    init_i3_addr_ipv4(&localI3Address, proxy->get_my_addr(), i3ProxyPort);
    
    //initialize I3 Address Book
    char addrBookFileName[MAX_FILENAME_LEN];
    readStringAttrib(ATTRIB_ADDRESS_BOOK, addrBookFileName, true);
   
    i3AddressBook = new I3AddressBook(addrBookFileName);
   
    //add the file descriptor for receiving I3 packets to the Proxy's core Select.
    TObjectFunctor<I3ClientContext> *fdfunc = new TObjectFunctor<I3ClientContext>(context, &I3ClientContext::receivedPacketFromOverlay);
    addFDCallback(context->getOverlayPktRcvFD(), fdfunc, true);

    addedTCPFDFlag = false;
    if (context->isTCPSupported() && context->isTCPInitOk()) {
        addFDCallback(context->getOverlayPktRcvTCPFD(), fdfunc, true);
	    //printf ("\n---->added tcp fd = %d\n", context->getOverlayPktRcvTCPFD());
        addedTCPFDFlag = true;
    }
    // if isTCPSupported is true and isTCPInitOk is false, 
    // tcp socket initialization will be reattempted by the ping thread
    // when information about i3 servers is available.
    
   
    if (enableFastConnectionStartup) {
        initAnycastTriggers();
    }
   
    // Start address change monitoring
    addAddressChangeCheckTimer();
   
    if (context->usePing()) { 
    	addServerUpdateTimer();
    }

#ifdef _WIN32
	scheduleUpdateStatus();
#endif


    // Start up the journal manager for i3 OCDs
    char tmpJrnlFileName[MAX_FILENAME_LEN];
    sprintf (tmpJrnlFileName, "I3.%s.jrnl", id.c_str());
    journalManager = new JournalManager (oci, this, tmpJrnlFileName, recoverFromCrash);

#ifdef _WIN32
	// Set the list of icons associated with the i3OCD
    setMonitor_IconList (string("i3_main.ico,i3_srv.ico,i3_disconnect.ico,i3_stop.ico,i3_run.ico"));
	setMonitor_CurrentIcon (string("i3_disconnect.ico"));
	setMonitor_CurrentDescription (description);
	setMonitor_CurrentStatusMsg (string ("Initializing"));
#endif

}


/**
  * Load and insert all triggers specified without a DNS name.
  * i.e.  triggers directly specified as id --> IP address
  */
void I3OverlayNetwork::insertTriggers () {

    // Insert each of the triggers in the list.
    list<MyName *>::iterator itr = myNameList.begin();
    while (itr != myNameList.end()) {

        MyName *currName = (*itr);
        
        char *trigType = currName->getProperty (ATTRIB_I3_MY_NAME_TRIGGER_TYPE);
        
        if (strcmp(trigType, "public") == 0) {
            //This name should be a public trigger.

            char *tmpStr = NULL;
            
            string keyStr = "";
            tmpStr = currName->getProperty (ATTRIB_I3_MY_NAME_KEY_STR);
            if (tmpStr != NULL) {
                keyStr = tmpStr;
            }
            
            string nameList = "";
            tmpStr = currName->getProperty (ATTRIB_I3_MY_NAME_NAME_STACK);
            if (tmpStr != NULL) {
                nameList = tmpStr;
            }

            string trigStack = "";
            tmpStr = currName->getProperty (ATTRIB_I3_MY_NAME_ID_STACK);
            if (tmpStr != NULL) {
                trigStack = tmpStr;
            }
            
            PublicTrigger*  pubTrig = new PublicTrigger (
                                    currName->name,
                                    keyStr,
                                    trigStack,
                                    nameList,
                                    this
                                );
            pubTrig->triggerType = trigType;


            int tmpMaxConn = -1;
            tmpStr = currName->getProperty (ATTRIB_I3_MY_NAME_MAX_CONN);
            if (tmpStr != NULL) {
                tmpMaxConn = atoi (tmpStr);
            }   

            int tmpMaxBW = -1;
            tmpStr = currName->getProperty (ATTRIB_I3_MY_NAME_MAX_BW);
            if (tmpStr != NULL) {
                tmpMaxBW = atoi (tmpStr);
            }

            pubTrig->setRateLimit (tmpMaxConn, tmpMaxBW);

            insertPublicTrigger (pubTrig);
        
        } else {
            //private triggers
           
            char* tmpIdStr = currName->getProperty (ATTRIB_I3_MY_NAME_I3_ID);
            if (tmpIdStr == NULL) {
                I3_PRINT_INFO2(
                    INFO_LEVEL_WARNING,
                    "Required attribute %s missing for private trigger in OCD %s\n",
                    ATTRIB_I3_MY_NAME_I3_ID,
                    id.c_str()
                );
                return; 
            }

            ID tmpId;
            I3Id::convertStr2I3Id (tmpIdStr, &tmpId);

            //TODO Should this be private.  Rmember to change the place the trigger time
            // in the code used to insert this trigger also.
            cl_set_private_id (&tmpId);

            if (currName->name != "") {
                addNameById (&tmpId, currName->name);
            }

            I3Trigger *currTrig = new I3Trigger (&tmpId, this);
            currTrig->triggerType = trigType;

            insertPrivateTrigger (currTrig);
            
       }
        itr++;
    }
}

/** Insert the specified private trigger.
  */
void I3OverlayNetwork::insertPrivateTrigger (I3Trigger *currTrig) {

    // TODO QQQ: Are keys necessary for these kind of triggers??
    Key key;
    I3Key::setRandomKey (&key);
    currTrig->i3Key = new I3Key();
    memcpy(&(currTrig->i3Key->key), &key, sizeof(Key));

    int retCode;
    //TODO QQQ: Should this kind of trigger be public or private?
    int trigFlags = CL_TRIGGER_CFLAG_R_CONSTRAINT | CL_TRIGGER_CFLAG_PRIVATE;
    currTrig->cl_trig = context->createTrigger(&(currTrig->i3Id->id), PREFIX_LEN, &key, trigFlags , &retCode);

    //register the callback to be executed when this trigger insertion is acked.
    I3ObjectFunctor<I3OverlayNetwork> *trigFuncInsert = new I3ObjectFunctor<I3OverlayNetwork>(this, &I3OverlayNetwork::insertedTrigger);
    currTrig->registerCallback(trigFuncInsert, CL_CBK_TRIGGER_INSERTED);

    //register the callback to be executed when events other than trigger insertion ack
    //is received on this trigger.
    I3ObjectFunctor<I3OverlayNetwork> *trigFuncEvent = new I3ObjectFunctor<I3OverlayNetwork>(this, &I3OverlayNetwork::receivedTriggerEvent);
    currTrig->registerCallback(trigFuncEvent, CL_CBK_RECEIVE_PACKET);
    context->registerTriggerCallback(currTrig->cl_trig, CL_CBK_TRIGGER_INSERTED, dummy_insertedTrigger, currTrig);
    context->registerTriggerCallback(currTrig->cl_trig, CL_CBK_TRIGGER_CONSTRAINT_FAILED, dummy_constraint_failed, currTrig);
    context->registerTriggerCallback(currTrig->cl_trig, CL_CBK_RECEIVE_PACKET, dummy_receive_packet, currTrig);
    context->registerTriggerCallback(currTrig->cl_trig, CL_CBK_TRIGGER_REFRESH_FAILED, dummy_trigger_refresh_failed, currTrig);
    context->registerContextCallback(CL_CBK_TRIGGER_NOT_FOUND, dummy_triggerNotFound, this);
    if (retCode != CL_RET_OK) {
        I3_PRINT_DEBUG0(I3_DEBUG_LEVEL_MINIMAL, "Unable to createTrigger with id!\n");
    }    
    insertTrigger(currTrig, enableShortcut?CL_IFLAGS_TRIGGER_ALLOW_SHORTCUT:0);

}

/**
  * This function inserts the specified public trigger into I3
  * infrastructure.
  */
void I3OverlayNetwork::insertPublicTrigger(PublicTrigger *trig) {
    
    if ( trig->i3Key == NULL ) {
        I3_PRINT_INFO1(INFO_LEVEL_MINIMAL, "I3 key not present for public trigger %s."
                        "Public trigger not inserted!\n",
                        trig->i3DNS.c_str());
        return;
    }


    
  /* XXX: just simply call alloc for now; preallocate a pool of buffers
     in the future */
  //dns = (struct pub_i3_dns *) malloc( sizeof(struct pub_i3_dns) );
 
    I3_PRINT_DEBUG1(I3_DEBUG_LEVEL_VERBOSE, "Inserting public trigger %s.\n", trig->i3DNS.c_str());

    ID* lookedUpId = i3AddressBook->lookup_addrbook(trig->i3DNS.c_str());

    if ( lookedUpId != NULL) {
        trig->setI3Id(lookedUpId);
        trig->nameHashedFlag = false;
        
    } else if ( enableHashedURLs ) {
            
            trig->createNewBlankId();
            I3Id::hash_URL_on_ID(trig->i3DNS.c_str(), &(trig->i3Id->id));

            trig->nameHashedFlag = true; 
            
            char tmpBuf[MAX_PRINT_BUF];
            I3_PRINT_DEBUG2(DEBUG_LEVEL_VERBOSE, "insertPublicTrigger: %s---->%s", trig->i3DNS.c_str(), sprintf_i3_id(tmpBuf, &trig->i3Id->id));

            I3_PRINT_DEBUG1 (
                        DEBUG_LEVEL_VERBOSE,
                        "The requested name %s is not in your address book.\n"
                        "So the i3 id of the public trigger will be constructed by "
                        "hashing the name.\n",
                        trig->i3DNS.c_str()
                    );
                        
    } else {
        I3_PRINT_INFO1(I3_INFO_LEVEL_WARNING,
                    "Public trigger for inserting %s not"
                    " specified in address book."
                    "Trigger not inserted.\n",
                    trig->i3DNS.c_str());
        return;
    }

    /* ensure that the ID is public_id */
    if ( ! trig->i3Id->isPublic()) {  //TODO avoid public check for name hashed ids
        I3_PRINT_INFO1(I3_INFO_LEVEL_WARNING, 
                "Attempting to insert public trigger for %s "
                "that does not have public_id bit set.\n", 
                trig->i3DNS.c_str());
    }


    int retCode;
   
    int trigFlags = 0;

    if (trig->stack == "") {
        // This trigger points to my IP address and not to a stack.
    
        //finally insert the trigger.
        Key *trigKey = NULL;
    
        if ( ! trig->nameHashedFlag ) {
                
            trigFlags = CL_TRIGGER_CFLAG_L_CONSTRAINT | CL_TRIGGER_CFLAG_PUBLIC;
            trigKey = &(trig->i3Key->key);    
        } else {
            
            //if the id of the trigger was generated by hashing the name.
            trigFlags = CL_TRIGGER_CFLAG_R_CONSTRAINT | CL_TRIGGER_CFLAG_PRIVATE;
            trigKey = NULL; //TODO
            trigKey = &(trig->i3Key->key);    //Put only one of these statments TODO TODO TODO
        }
            
        trig->cl_trig = context->createTrigger(&(trig->i3Id->id), ID_LEN_BITS, trigKey, trigFlags , &retCode);
    
        //register the callback to be executed when this trigger insertion is acked.
        I3ObjectFunctor<I3OverlayNetwork> *trigFuncInsert = new I3ObjectFunctor<I3OverlayNetwork>(this, &I3OverlayNetwork::insertedTrigger);
        trig->registerCallback(trigFuncInsert, CL_CBK_TRIGGER_INSERTED);
        
        //register the callback to be executed when events other than trigger insertion ack
        //is received on this trigger.
        I3ObjectFunctor<I3OverlayNetwork> *trigFuncEvent = new I3ObjectFunctor<I3OverlayNetwork>(this, &I3OverlayNetwork::receivedTriggerEvent);
        trig->registerCallback(trigFuncEvent, CL_CBK_RECEIVE_PACKET);
    
        context->registerTriggerCallback(trig->cl_trig, CL_CBK_TRIGGER_INSERTED, dummy_insertedTrigger, trig);
        context->registerTriggerCallback(trig->cl_trig, CL_CBK_TRIGGER_CONSTRAINT_FAILED, dummy_constraint_failed, trig);
        context->registerTriggerCallback(trig->cl_trig, CL_CBK_RECEIVE_PACKET, dummy_receive_packet, trig);
        context->registerTriggerCallback(trig->cl_trig, CL_CBK_TRIGGER_REFRESH_FAILED, dummy_trigger_refresh_failed, trig);
        context->registerContextCallback(CL_CBK_TRIGGER_NOT_FOUND, dummy_triggerNotFound, this);
    
        if (retCode != CL_RET_OK) {
            I3_PRINT_DEBUG0(I3_DEBUG_LEVEL_MINIMAL, "Unable to createTrigger!\n");
        }
    
    } else {

        // This trigger points to a stack of ids.
        trigFlags = CL_TRIGGER_CFLAG_R_CONSTRAINT | CL_TRIGGER_CFLAG_PRIVATE;   //TODO is this constraining necessary?
        trig->cl_trig = context->createTriggerStack (&(trig->i3Id->id), ID_LEN_BITS, trig->stack, trigFlags, &retCode);
    }
       
    
    insertTrigger(trig, enableShortcut?CL_IFLAGS_TRIGGER_ALLOW_SHORTCUT:0);
    
}
/**
  * This function inserts the specified i3 trigger.  It also registers a timeout event for the insert operation.
  * All required fields of the trigger (eg: i3Id, i3Key) should be available before this function is called.
  * This function also adds the trigger to the trigger-id hashmap.
  * @param trig The trigger to be inserted.
  * @param insertFlags Flags associated with trigger insertiong - for eg: CL_IFLAGS_TRIGGER_LOCAL
  */
void I3OverlayNetwork::insertTrigger(I3Trigger *trig, uint8_t insertFlags) {
    
    addTrigger(trig);   //adds the trigger to trigger-id hashmap

    int retCode = context->insertTrigger(trig, insertFlags);
    
    if (retCode != CL_RET_OK) {
        I3_PRINT_DEBUG0(I3_DEBUG_LEVEL_MINIMAL, "Unable to context->createTrigger!\n");
    }
    //TODO callbacks, refreshing incorporating with API

    trig->insertAttemptsCount++;
    
    // Insertion timeout is set in I3ClientContext
}


/**
 * Request a private trigger from the remote end point of the
 * specified virtual node.
 * A request retry timeout is set.
 */
void I3OverlayNetwork::requestPrivateTrigger(I3OCDStateInfo *ocdState) {

    assert (ocdState != NULL);

    I3_PRINT_DEBUG1 (   
                    I3_DEBUG_LEVEL_VERBOSE,
                    "Requesting private trigger from %s.\n",
                    ocdState->endPointName
                );

    if (ocdState->prvTriggerConfirmationTimer != NULL) {
        ocdState->prvTriggerConfirmationTimer->setDisabled();
        ocdState->prvTriggerConfirmationTimer = NULL;
    }

    if (proxy->get_stopProxyFlag()) {
        return;
    }
    
    // We have requested for a private trigger too many times.  We give up.
    // Reply NOT FOUND to any DNS requests queued on the virtual node.
    if (ocdState->numRemotePrivateIdRequests > I3_MAX_NUM_REMOTE_PRIVATE_ID_REQUESTS) {
	
	    char tmpDNSBuf[MAX_PRINT_BUF];

	    if (strlen(ocdState->endPointName) == 0) {
	        sprintf(tmpDNSBuf, "%s", ocdState->endPointName);
	    } else {
	        sprintf(tmpDNSBuf, "[UNKNOWN DNS NAME]");
	    }
        I3_PRINT_INFO2 (
		    I3_INFO_LEVEL_MINIMAL,
		    "ocdState=%p: Tried to obtain private trigger from remote end point %s.  I give up requesting private triggers.",
		    ocdState, tmpDNSBuf
		);

        // Notify failure to all the OCIs waiting for this setup to complete.
        ocdState->notifySetupFailure();
        
	return;
    }
  
    ocdState->numRemotePrivateIdRequests ++; 

    // Add this OCD State to the hash table which keeps track of private
    // trigger requests made.
    addPrivTrigReqOCDState(ocdState);
   
    if (ocdState->remotePublicId != NULL) {
        
        I3_PRINT_DEBUG4 (
		        DEBUG_LEVEL_SUPER, 
		        "ocdState=%p: Sending private trigger request to %s(%s) for the %d th time.\n", 
                        ocdState,
		        ocdState->endPointName,
		        sprintf_i3_id(tmpBuf, &(ocdState->remotePublicId->id)),
		        ocdState->numRemotePrivateIdRequests
		    );
    } else if (ocdState->remotePublicIdStack.ids != NULL) {
         I3_PRINT_DEBUG3 (
		        DEBUG_LEVEL_SUPER, 
		        "Sending private trigger request to stack %s(%s) for the %d th time.\n", 
		        ocdState->endPointName,
		        sprintf_i3_id(tmpBuf, &(ocdState->remotePublicIdStack.ids[0])),
		        ocdState->numRemotePrivateIdRequests
		    );
    } else {
        
        I3_PRINT_DEBUG0 (
                        DEBUG_LEVEL_SUPER,
                        "ERROR: Both public trigger id and stack are NULL\n"
                    );
        return;
    }
    
    cl_buf* clb;
    
    clb = packPrivateTriggerRequest (
                                            ocdState,
                                            &(ocdState->prv_id)
                                        );
        
    context->sendToStack (&(ocdState->remotePublicIdStack), clb,0);
            
    
    // Set up a timeout after which the private trigger request must be retried
    // if a private trigger confirmation is not received.
    if (! proxy->get_stopProxyFlag() ) { 
        I3ObjectFunctor<I3OverlayNetwork> *prvTriggerCnfFunctor = 
	                    new I3ObjectFunctor<I3OverlayNetwork>(
                                this, 
                                &I3OverlayNetwork::requestPrivateTrigger, 
                                ocdState
                            );

        ocdState->prvTriggerConfirmationTimer = I3TimerEvent::create (
                                                            PRIVATE_TRIGGER_REQUEST_TIMEOUT, 0, 
	                                                        (I3Functor *)prvTriggerCnfFunctor, 
                                                            "Private Trigger Confirmation Timer",
                                                            true);
   
        addTimerEvent(ocdState->prvTriggerConfirmationTimer);
    }

}


/**
  * Create a I3 data packet using the data in dataPacket.
  * Basically, this function puts a PROXY_DATA data block in the specified buffer.
  * This function can be modified to include additional blocks.
  * @param i3VN The virtual node for which the data is packed.
  */
void I3OverlayNetwork::packPacket (cl_buf* clb, char *pktContents, int pktSize, I3OCDStateInfo* i3VN ) {

    if (i3VN->state == FAKE_STATE_OK
            || (i3VN->state == FAKE_STATE_CNF && i3VN->enableFastConnectionSetup) //takes care of the fast connection case when the receiver has not finished inserting its private trigger.  But the receiver already knows the sender's private id.  So it can use the private id right away instead of the public id.
            ) {
        // the private trigger exchange was completed.
        I3GenericBlock * blk = (I3GenericBlock *) clb->data;


        memcpy(blk->genericBlock, pktContents, pktSize);
    
        I3OverlayNetwork::setI3Block ( (I3Block *) blk, I3_BLOCK_GENERIC, 0 /* last block */);
        clb->data_len = (pktSize + sizeof(I3GenericBlock));
 
        //assert (clb->data_len < 1200 /* MTU */);    //TODO
    
    } else {

        // If the private trigger confirmation was not received from the remote end point;
        // We are sending data to the public trigger of the remote end point
            
        I3GenericBlockViaPubTrig * blk = (I3GenericBlockViaPubTrig *) clb->data;
           
        memcpy (&blk->senderPrivId, &i3VN->prv_id, sizeof (ID));

        memcpy(blk->genericBlock, pktContents, pktSize);
 
        I3OverlayNetwork::setI3Block ( (I3Block *) blk, I3_BLOCK_GENERIC_VIA_PUB_TRIG, 0 /* last block */);
        clb->data_len = (pktSize + sizeof(I3GenericBlockViaPubTrig));
        
    }
}

/**
  * This function initializes the i3 specific fake state of an
  * I3OCDStateInfo.  A private id is generated and a trigger inserted.
  * A callback is inserted to handle the confirmation of the private trigger insert.
  * The activity check for this virtual node is also started.
  * @param ocdState The I3OCDStateInfo whose fake state is to be initialized.
  * @param fakeState This is used to distinguish between the initialization of 
  * VirtualNode at the client and initialization at the server.  i.e. when the 
  * private trigger is inserted because a legacy application made a DNS request,
  * the fakeState = FAKE_STATE_NEW.  When the private trigger is being inserted 
  * to satisfy a private trigger request from some other i3 proxy, the 
  * fakeState = FAKE_STATE_CNF
  * @param assocPubTrig The public trigger on which the private trigger request for this private trigger
  * was received, if any.  Otherwise, it is NULL.
  */
void I3OverlayNetwork::initFakeState(I3OCDStateInfo *i3VN, int fakeState, PublicTrigger* assocPubTrig) {
       

    if (i3VN->addr_type == I3_ADDR_TYPE_IPv4) {
//DANGEROUS    
#ifdef _WIN32
    	struct i3_addr i3_addr_tun;
    	memcpy(&i3_addr_tun, &localI3Address, sizeof(i3_addr));
    	i3_addr_tun.t.v4.addr.s_addr = ntohl(inet_addr(proxy->getTunnelIP()));
    	memcpy(&i3VN->localI3Address, &i3_addr_tun, sizeof(i3_addr));
#else
        memcpy(&i3VN->localI3Address, &localI3Address, sizeof(i3_addr));
#endif    
    } else {
        
        I3_PRINT_INFO0(
                I3_INFO_LEVEL_WARNING, 
                "\n Support for other than IPv4 is not implemented yet.\n"
                );
    }
    
    i3VN->state = fakeState;
 
    int trigInsertFlag = enableShortcut?CL_IFLAGS_TRIGGER_ALLOW_SHORTCUT:0;
    int trigCreateFlags = CL_TRIGGER_CFLAG_R_CONSTRAINT;
    
    if ( ! i3VN->crashRecoveryInProgress && 
            !enableFastConnectionStartup) {
	    // If crash recovery were in progress, the private id would have
	    // already been read in from the journal, i.e. there is no need
	    // to generate a new private key.  
	    // Here, we are not in crash recovery.
        // If we are in fast connection mode, again we do not need a private id -
        // we use anycast triggers.
        // If we are just trying to renew the trigger, we do not need to regenerate
        // a private key.
        
    	I3Id::gen_private_ID(&i3VN->prv_id);
  
		if (firstHopIdFlag) {
  			// if the firstHopId was specified.
			// Change the private trigger id so that it gets inserted in the first hop server.
					
		    int KKK = 10;
		    int i;
	    	for (i = 0; i < KKK ; i++) {
			    i3VN->prv_id.x[i] = firstHopId.x[i];
	    	}

	    	for(i = (KKK - 1); i>=0;i--) {
	      		if ( i3VN->prv_id.x[i] != 0) {
        			i3VN->prv_id.x[i]--;
	        		break;
    	  		}
      			else {
	        		i3VN->prv_id.x[i] = 0xff;
					}
    		}
		}

	    set_private_id (&(i3VN->prv_id));
	 
    } else if (enableFastConnectionStartup) {
        //An anycast trigger is to be inserted only if the local
        //i3overlay was configured to enableFastConnectionSetup.
        //It does not depend on what was enabled at the other end point.

        //We get a new local anycast trigger
        getNewLocalAnycastTriggerId (&i3VN->prv_id);
        trigInsertFlag = CL_IFLAGS_TRIGGER_LOCAL;
        memcpy ( &(i3VN->prv_trig_key), &(baseAnycastTrigger->i3Key->key), sizeof (Key));
        trigCreateFlags = CL_TRIGGER_CFLAG_R_CONSTRAINT | CL_TRIGGER_CFLAG_PRIVATE;
    }
   
    // Add this VN to a hash table, keyed by its private id 
    addLocalVN(i3VN);


    I3_PRINT_DEBUG1(
            I3_DEBUG_LEVEL_VERBOSE, 
            "Inserting private trigger while initializing fake state : %s.\n", 
            sprintf_i3_id(tmpBuf, &(i3VN->prv_id))
            );

    int retCode; 
    i3VN->prv_cl_trig = context->createTrigger(
                        &i3VN->prv_id, ID_LEN_BITS, &(i3VN->prv_trig_key), 
                        trigCreateFlags, &retCode);
    
    
    I3Trigger * trig = new I3Trigger(&i3VN->prv_id, this);
    
    if (assocPubTrig != NULL) {
        trig->setRateLimit (assocPubTrig->maxConn, assocPubTrig->maxBW);
    }

    if (retCode != CL_RET_OK) {
        I3_PRINT_DEBUG0(I3_DEBUG_LEVEL_MINIMAL, "Unable to createTrigger!\n");
    }
    context->registerTriggerCallback(i3VN->prv_cl_trig, 
                                    CL_CBK_TRIGGER_INSERTED, 
                                    dummy_insertedTrigger, 
                                    trig);
    
    context->registerTriggerCallback(i3VN->prv_cl_trig, 
                                    CL_CBK_TRIGGER_CONSTRAINT_FAILED, 
                                    dummy_constraint_failed, 
                                    trig);
  
    context->registerTriggerCallback(i3VN->prv_cl_trig, 
                                    CL_CBK_RECEIVE_PACKET, 
                                    dummy_receive_packet, 
                                    trig);
  
    context->registerTriggerCallback(i3VN->prv_cl_trig, 
                                    CL_CBK_TRIGGER_REFRESH_FAILED, 
                                    dummy_trigger_refresh_failed, 
                                    trig);

    
    trig->ocdState = i3VN;
    i3VN->localPrivateTrigger = trig;
    
    trig->cl_trig = i3VN->prv_cl_trig;

//printf ("\n\n\n\n\ntrigInsertFlag = %d\n\n\n\n", trigInsertFlag);
    insertTrigger(trig, trigInsertFlag);

    //register the callback to be executed when this trigger insertion is acked.
    I3ObjectFunctor<I3OverlayNetwork> *trigFuncInsert = 
                            new I3ObjectFunctor<I3OverlayNetwork>(
                                    this, &I3OverlayNetwork::insertedTrigger
                                );
    
    trig->registerCallback(trigFuncInsert, CL_CBK_TRIGGER_INSERTED);

    //register the callback to be executed when events other than trigger 
    // insertion ack is received on this trigger.
    I3ObjectFunctor<I3OverlayNetwork> *trigFuncEvent = 
      new I3ObjectFunctor<I3OverlayNetwork>(this, 
		 &I3OverlayNetwork::receivedTriggerEvent);
    trig->registerCallback(trigFuncEvent, CL_CBK_RECEIVE_PACKET);

    if (enableFastConnectionStartup) {
        // If any anycast trigger was inserted locally, there
        // is no callback when the trigger is inserted.
        // So we need to simulate the callback.
        insertedTrigger (trig, NULL);
    }
    
    //i3VN->startActiveChecking();
    //TODO: Set time out for the failure to insert this trigger
    return;
}

/**
  * Gives a string representation (pretty printed) of the I3OverlayNetwork.
  * @param tmpStr a character buffer in which the string is stored.
  * Sufficient space should be allocated for tmpStr.
  * @return pointer to tmpStr
  */
char* I3OverlayNetwork::toString(char *tmpStr) {

    sprintf( tmpStr,
            "I3 Overlay Network\n"
            "\ttype\t\t:\t%s\n"
            "\tid\t\t:\t%s\n"
            "\tdescription\t:\t%s\n"
            "\tconfig file\t:\t%s\n",
            type.c_str(),
            id.c_str(),
            description.c_str(),
            configFileName.c_str()
           );
    return tmpStr;
}

/**
  * Read in the values of some parameters from the I3 config file.
  * Some of the parameter values may be read elsewhere.
  */
void I3OverlayNetwork::initConfigValues() {
    
    //configFile->readStringParam("//LocalIPAddress", tmpIPBuf, true);
    //local_ip_addr.s_addr = ntohl(inet_addr(tmpIPBuf));
    //TODO: XXX: How should the local IP address be determined?
    // -- through config file or by dynamic probing happening now?
    // Right now, we do dynamic probing.

    //initialize local and port number used by this i3 overlay instance
    readUShortAttrib(ATTRIB_LOCAL_PORT_NUM, &i3ProxyPort, true);
    
    
    //I3_PRINT_INFO3(INFO_LEVEL_VERBOSE, "I3Overlay (%s): LocalIPAddress=%s LocalPortNum=%u\n", id.c_str(), tmpIPBuf, i3ProxyPort); 

    // enable hashed urls?
    unsigned short defaultEnableHashedURLs = 1;
    readUShortAttrib(ATTRIB_ENABLE_HASHED_URLS, &enableHashedURLs, defaultEnableHashedURLs);

    char tmpFastStartup[MAX_PARAM_LEN];
    strcpy (tmpFastStartup, "no");  //default value
    readStringAttrib(ATTRIB_ENABLE_FAST_CONNECTION_STARTUP, tmpFastStartup, false);
    if (    (strcasecmp (tmpFastStartup, "yes") == 0) ||
            (strcasecmp (tmpFastStartup, "true") == 0) ) {
    
        enableFastConnectionStartup = true;
    } else {
        enableFastConnectionStartup = false;
    }

    char tmpShortcut[MAX_PARAM_LEN];
    strcpy (tmpShortcut, "no");  //default value
    readStringAttrib(ATTRIB_ENABLE_SHORTCUT, tmpShortcut, false);
    if (    (strcasecmp (tmpShortcut, "yes") == 0) ||
            (strcasecmp (tmpShortcut, "true") == 0) ) {
    
        enableShortcut = true;
    } else {
        enableShortcut = false;
    }


	firstHopIdFlag = false;
	if (readStringAttrib("ClosestI3Server", closestI3Server, false)) {
		// the closest server was specified.
		firstHopId = atoi3id (closestI3Server);
		firstHopIdFlag = true;
	}

}

/**
  * This function looks up the I3Trigger object with the specified id.
  * @param id The I3 id of the trigger being looked up.
  * @return the I3Trigger if found, else NULL
  */
I3Trigger* I3OverlayNetwork::lookupTrigger(ID id) {

    string tmpIdStr = I3Id::convertIdToStr(id);
    I3_PRINT_DEBUG1(
                I3_DEBUG_LEVEL_VERBOSE, 
                "Looking for trigger with id %s.\n", 
                sprintf_i3_id(tmpBuf, &id)
            );
    
    map<string, I3Trigger*>::iterator itr = i3TriggerMap.find(tmpIdStr);
    

    if (itr != i3TriggerMap.end()) {
        return (I3Trigger*)itr->second;
        
    } else {
            
        return NULL;
    }   
}

/**
  * This function looks up the I3OCDStateInfo object with the specified public id
  * from the remote private trigger request map.
  * @return The corresponding I3OCDStateInfo ptr if found, else NULL
  */
I3OCDStateInfo* I3OverlayNetwork::lookupPrivTrigReqMap (ID id) {

    string tmpIdStr = I3Id::convertIdToStr(id);
    map<string, I3OCDStateInfo*>::iterator itr = privTrigReqMap.find(tmpIdStr);
    
    if (itr != privTrigReqMap.end()) {
        return (I3OCDStateInfo*)itr->second;
        
    } else {
            
        return NULL;
    }   
}

/**
  * This function looks up the I3OCDStateInfo object with the specified remote Id.
  * @param id The remote Id being looked up
  * @return The corresponding I3OCDStateInfo ptr if found, else NULL
  */
I3OCDStateInfo* I3OverlayNetwork::lookupRemoteVN(ID id) {

    string tmpIdStr = I3Id::convertIdToStr(id);
    map<string, I3OCDStateInfo*>::iterator itr = remoteVNMap.find(tmpIdStr);
    
    if (itr != remoteVNMap.end()) {
        return (I3OCDStateInfo*)itr->second;
        
    } else {
            
        return NULL;
    }   
}
/**
  * This function looks up the I3OCDStateInfo object with the specified local Id.
  * @param id The local Id being looked up
  * @return The corresponding I3OCDStateInfo ptr if found, else NULL
  */
I3OCDStateInfo* I3OverlayNetwork::lookupLocalVN(ID id) {

    string tmpIdStr = I3Id::convertIdToStr(id);
    map<string, I3OCDStateInfo*>::iterator itr = localVNMap.find(tmpIdStr);
    
    if (itr != localVNMap.end()) {
        return (I3OCDStateInfo*)itr->second;
        
    } else {
            
        return NULL;
    }   
}

/** 
  * This function adds the specified I3OCDStateInfo to the hash table
  * which keeps track of pending private trigger requests.
  * @param ocdState Pointer to the I3OCDStateInfo to be added.
  */
void I3OverlayNetwork::addPrivTrigReqOCDState (I3OCDStateInfo* ocdState) {

    ID tmpId;
    
    if (ocdState->remotePublicId != NULL) {
        memcpy (&tmpId, &ocdState->remotePublicId->id, sizeof(ID));
    } else if (ocdState->remotePublicIdStack.ids != NULL) {
        memcpy (&tmpId, & (ocdState->remotePublicIdStack.ids[0]), sizeof (ID));
    } else {
        I3_PRINT_DEBUG0 (
                    DEBUG_LEVEL_SUPER,
                    "ERROR: both remotePublicId and remotePublicIdStack are NULL!\n"
                );
        return;
    }
    
    string tmpIdStr = I3Id::convertIdToStr(tmpId);
   
    I3OCDStateInfo *test = lookupPrivTrigReqMap (tmpId);
    if (test != ocdState) {
        //avoid multiple copies.
        privTrigReqMap.insert(pair<string, I3OCDStateInfo*>(tmpIdStr, ocdState));
    }
}

/** 
  * This function adds the specified I3OCDStateInfo to the localVNMap, keyed by the local Id.
  * @param ocdState Pointer to the I3OCDStateInfo to be added.
  */
void I3OverlayNetwork::addLocalVN(I3OCDStateInfo* ocdState) {
    string tmpIdStr = I3Id::convertIdToStr(ocdState->prv_id);
    
    localVNMap.insert(pair<string, I3OCDStateInfo*>(tmpIdStr, ocdState));
}

/** 
  * This function adds the specified I3OCDStateInfo to the remoteVNMap, keyed by the remote private Id.
  * @param ocdState Pointer to the I3OCDStateInfo to be added.
  */
void I3OverlayNetwork::addRemoteVN(I3OCDStateInfo* ocdState) {
    string tmpIdStr = I3Id::convertIdToStr(ocdState->remotePrivateId->id);
    
    remoteVNMap.insert(pair<string, I3OCDStateInfo*>(tmpIdStr, ocdState));
}

/** 
  * This function removes the specified I3OCDStateInfo from the localVNMap
  */
void I3OverlayNetwork::removeLocalVN(I3OCDStateInfo* ocdState) {
    string tmpIdStr = I3Id::convertIdToStr(ocdState->prv_id);
    
    localVNMap.erase(tmpIdStr);
}

/** 
  * This function removes the specified I3OCDStateInfo from the private trig req map.
  */
void I3OverlayNetwork::delPrivTrigReqOCDState (ID id) {
    string tmpIdStr = I3Id::convertIdToStr(id);
    
    privTrigReqMap.erase(tmpIdStr);
}
/** 
  * This function removes the specified I3OCDStateInfo from the remoteVNMap
  */
void I3OverlayNetwork::removeRemoteVN(I3OCDStateInfo* ocdState) {
   
    if (ocdState->remotePrivateId != NULL) {
        string tmpIdStr = I3Id::convertIdToStr(ocdState->remotePrivateId->id);
        remoteVNMap.erase(tmpIdStr);
    }
    
}

/** 
  * This function adds the specified trigger to the trigger map.
  * The trigger is not added if there already exists a trigger with the same id.
  * @param trig The trigger to be added.
  */
void I3OverlayNetwork::addTrigger(I3Trigger *trig) {

    I3Trigger* tmpTrig = lookupTrigger(trig->i3Id->id);
    
    if (tmpTrig == NULL) {
        // trigger does not already exist in the hash table
        string tmpIdStr = I3Id::convertIdToStr(trig->i3Id->id);
        I3_PRINT_DEBUG1(
                I3_DEBUG_LEVEL_VERBOSE, 
                "Adding Trigger with id %s.", 
                trig->i3Id->toString(tmpBuf)
                );
        
        i3TriggerMap.insert(pair<string, I3Trigger*>(tmpIdStr, trig));
        
    } else {
            
        I3_PRINT_DEBUG1(
                I3_DEBUG_LEVEL_MINIMAL, 
                "Attempting to insert the following duplicate trigger %s"//
                "into the proxy trigger hash table.\n", 
                trig->i3Id->toString(tmpBuf)
            );

    }
}

/**
  * This function removes the specified trigger from the i3 trigger map.
  */
void I3OverlayNetwork::removeTrigger(I3Trigger *trig) {
    
    string tmpIdStr = I3Id::convertIdToStr(trig->i3Id->id);
    i3TriggerMap.erase(tmpIdStr);
    trig->killMeFlag = true;
        
}

/**
  * Destroys the specified i3 virtual node.
  * It first does the I3 specific destruction like setting the 
  * local private trigger for destruction.
  * Then the Proxy's destroyVN is called to do further clean up.
  */
void I3OverlayNetwork::destroyVN(I3OCDStateInfo *ocdState) {

    assert (ocdState != NULL);
    
    if (ocdState->localPrivateTrigger != NULL) {
        removeRemoteVN(ocdState);
        removeLocalVN(ocdState);

        removeTrigger(ocdState->localPrivateTrigger);
        // At the next timer event which is to refresh the trigger,
        // destroy the trigger instead of doing the refresh.

    }
    
        // Disable any active timers
        if (ocdState->prvTriggerConfirmationTimer != NULL) {
           ocdState->prvTriggerConfirmationTimer->setDisabled(); 
           ocdState->prvTriggerConfirmationTimer = NULL;
        }

        if (ocdState->localPrivateTrigger !=  NULL && ocdState->localPrivateTrigger->timer !=  NULL) {
            ocdState->localPrivateTrigger->timer->setDisabled();
            ocdState->localPrivateTrigger->timer = NULL;
        }

    if (ocdState->remotePublicId != NULL) {
        delPrivTrigReqOCDState (ocdState->remotePublicId->id);
    }

}


/** 
  * Restore the state associated with the specified journal entry.
 */
void I3OverlayNetwork::recoverRecord(char *tmpJournalBuf) {

	//Construct an I3OCDStateInfo with the information contained
	//in the journal record.  This I3OCDStateInfo constructor
	//parses the journal record.
    I3OCDStateInfo *tmpOCDState = I3OCDStateInfo::constructState (tmpJournalBuf,  oci, this);
	
    if (tmpOCDState != NULL) {
   
	    addOCDState(tmpOCDState);
        putStateInfo (tmpOCDState->myHandle, tmpOCDState);
        putEndPoint (tmpOCDState->endPointName, tmpOCDState);
        
        if (tmpOCDState->i3VNType == I3_VN_TYPE_LOCAL_CREATED) {
	        // reinsert local private trigger and  request remote private trigger
	        initFakeState(tmpOCDState, FAKE_STATE_NEW, NULL);
        
        } else if (tmpOCDState->i3VNType == I3_VN_TYPE_REMOTE_CREATED) {
            initFakeState(tmpOCDState, FAKE_STATE_CNF, NULL);
        
        } else {
            I3_PRINT_DEBUG0 (
                I3_DEBUG_LEVEL_MINIMAL,
                "Unknown i3VNType encountered during crash recovery\n"
                );
        }
    } else {

        I3_PRINT_DEBUG1 (
                        DEBUG_LEVEL_SUPER,
                        "Error while restoring state associated with journal record: %s\n",
                        tmpJournalBuf
                    );
    }
}

/**
 * Returns i3 specific status information 
 */
int I3OverlayNetwork::getStatus() {
    return context->getNumKnownI3Servers();
}

/** Fill the details of an I3Block */
void I3OverlayNetwork::setI3Block (I3Block *i3Blk, uint8_t i3MsgType, uint16_t blkLen) {
    
    i3Blk->blockType = i3MsgType;
    i3Blk->nextBlock = blkLen;
    
}

/**
  * This function is used to create a private trigger request
  * for the specified id.
  * @param ocdState The VirtualNode for which the private trigger request is being made.
  * @param id The i3 id requesting the private trigger, i.e. the id to which the private trigger confirmation is to be sent back.
  * @param certificateRequired Are requesting a certificate (for authentication) in addition to the private trigger?
  * @param certName The name for which a certificate is requested.  This value is used only in certificateRequired
  * is true.
  */
cl_buf * I3OverlayNetwork::packPrivateTriggerRequest(I3OCDStateInfo *ocdState, ID* id) {

    static cl_buf *clb = NULL;
    if (NULL == clb) {
        clb =  cl_alloc_buf (MAX_PACKET_BUF_LEN);
    }

    int offset = 0;
   
    /*
    // START - DNS Name + pref str
    // information should actually be put in by a layer below the overlay.
    ProxySetupBlock *proxySetupBlk = (ProxySetupBlock *) clb->data;
    strcpy (proxySetupBlk->prefStr, ocdState->dnsPacket->reqURL.c_str());

    offset += sizeof (ProxySetupBlock);
    // END - DNS name + pref str
    */
    
    // Pack the i3 specific headers before any generic headers.
    // This is a MUST.

        I3PrivateTriggerRequest *trigReqBlock = (I3PrivateTriggerRequest *) (clb->data + offset);

        // Set the top level headers
        I3OverlayNetwork::setI3Block ( (I3Block *) trigReqBlock, I3_BLOCK_PRIVATE_TRIG_REQ, 0 /* last block */);
   
        memcpy ( (void *) &trigReqBlock->senderPrivId, (void *) id, ID_LEN);
  
        // if fast connection is enabled here, request the same from the other endpoint.
        memcpy (    &trigReqBlock->enableFastConnectionSetup, 
                    &enableFastConnectionStartup, 
                    sizeof (enableFastConnectionStartup)
                );
    
        offset += sizeof (I3PrivateTriggerRequest);

        // Now pack the i3 independent block.
        I3GenericBlock* genericBlock = (I3GenericBlock *) (clb->data + offset);
    
        // Set the top level headers
        I3OverlayNetwork::setI3Block ( (I3Block *) genericBlock, I3_BLOCK_GENERIC, 0 /* last block */);

        int genBlockSize = ocdState->setupOptionLen; /* TODO FIX ocdState->packToSendBlocks(genericBlock->genericBlock) ; */
        memcpy (genericBlock->genericBlock, ocdState->setupOptionBlocks, ocdState->setupOptionLen);

        if (genBlockSize == 0) {
            // no generic blocks to be piggybacked
            clb->data_len = clb->max_len = offset;
            trigReqBlock->headerBlock.piggybackLen = 0;
        } else {
    
            clb->data_len = clb->max_len = offset + (genBlockSize + sizeof (I3GenericBlock));
            trigReqBlock->headerBlock.piggybackLen = genBlockSize + sizeof (I3GenericBlock);
        }
    return clb;
}



/**
  * This function is used to create a private trigger confirmation packet
  * for the specified id.
  * If a certificate is specified, it is also packed into the packet.
  *
  * @param ocdState The VirtualNode associated with the private trigger confirmation
  * @param id The id of the private trigger from which the confirmation is sent.
  * i.e. the id of the private trigger created as a result of a private trigger request.
  */
cl_buf* I3OverlayNetwork::packPrivateTriggerConfirmation(I3OCDStateInfo *ocdState, ID  *id) {
    
    
    static cl_buf *clb = NULL;
    if (NULL == clb) {
        clb =  cl_alloc_buf (MAX_PACKET_BUF_LEN);
    }
 
    int clb_data_offset = 0;

    // Pack the I3 specific blocks first.  This is a MUST.
    I3PrivateTriggerReply *trigReplyBlock = (I3PrivateTriggerReply *) (clb->data + clb_data_offset);

    // Set the top level headers
    I3OverlayNetwork::setI3Block ( (I3Block *) trigReplyBlock, I3_BLOCK_PRIVATE_TRIG_CNF, 0 /* last block */);
   
    memcpy ( (void *) &trigReplyBlock->privTrigId, (void *) id, ID_LEN);
  
    clb_data_offset = sizeof (I3PrivateTriggerReply);
 
    // Now pack the i3 independent block.
    I3GenericBlock* genericBlock = (I3GenericBlock *) (clb->data + clb_data_offset);
    
    // Set the top level headers
    I3OverlayNetwork::setI3Block ( (I3Block *) genericBlock, I3_BLOCK_GENERIC, 0 /* last block */);

    int genBlockSize = ocdState->setupOptionLen; /* TODO FIX ocdState->packToSendBlocks(genericBlock->genericBlock) ; */
    memcpy (genericBlock->genericBlock, ocdState->setupOptionBlocks, ocdState->setupOptionLen);

    if (genBlockSize == 0) {
        clb->data_len = clb->max_len = clb_data_offset;
        trigReplyBlock->headerBlock.piggybackLen = 0;
    } else {
        clb->data_len = clb->max_len = clb_data_offset + (genBlockSize + sizeof(I3GenericBlock));
        trigReplyBlock->headerBlock.piggybackLen = genBlockSize + sizeof (I3GenericBlock); // Because this is the last block
    }
    return clb;
}


/**
  * This function inserts the anycast triggers for use in the case of 
  * fast setup connections.
  */
void I3OverlayNetwork::initAnycastTriggers () {

    assert(false);
    printf("initAnyCast: should not be printed\n");
 
    nextAnycastIndex = 1;
    string randStr = generateRandomStr(tmpBuf);
    I3Id* tmpId = I3Id::generateI3Id ( randStr, I3_ID_TYPE_PRIVATE);
    
    baseAnycastTrigger = new I3Trigger(&(tmpId->id), this);
    baseAnycastTrigger->isAnycastFlag = true;

    //register the callback to be executed when this trigger insertion is acked.
    I3ObjectFunctor<I3OverlayNetwork> *trigFuncInsert = new I3ObjectFunctor<I3OverlayNetwork>(this, &I3OverlayNetwork::insertedTrigger);
    baseAnycastTrigger->registerCallback(trigFuncInsert, CL_CBK_TRIGGER_INSERTED);
    
    //register the callback to be executed when events other than trigger insertion ack
    //is received on this trigger.
    I3ObjectFunctor<I3OverlayNetwork> *trigFuncEvent = new I3ObjectFunctor<I3OverlayNetwork>(this, &I3OverlayNetwork::receivedTriggerEvent);
    baseAnycastTrigger->registerCallback(trigFuncEvent, CL_CBK_RECEIVE_PACKET);

 
    Key key;
    I3Key::setRandomKey (&key);
    baseAnycastTrigger->i3Key = new I3Key();
    memcpy(&(baseAnycastTrigger->i3Key->key), &key, sizeof(Key));

    int retCode;
   
    //TODO QQQ: Should the anycast trigger be public or private?
    int trigFlags = CL_TRIGGER_CFLAG_R_CONSTRAINT | CL_TRIGGER_CFLAG_PRIVATE;
    
    baseAnycastTrigger->cl_trig = context->createTrigger(&(baseAnycastTrigger->i3Id->id), MIN_PREFIX_LEN, &key, trigFlags , &retCode);
  
    context->registerTriggerCallback(baseAnycastTrigger->cl_trig, CL_CBK_TRIGGER_INSERTED, dummy_insertedTrigger, baseAnycastTrigger);
    
    context->registerTriggerCallback(baseAnycastTrigger->cl_trig, CL_CBK_TRIGGER_CONSTRAINT_FAILED, dummy_constraint_failed, baseAnycastTrigger);
  
    context->registerTriggerCallback(baseAnycastTrigger->cl_trig, CL_CBK_RECEIVE_PACKET, dummy_receive_packet, baseAnycastTrigger);
  
    context->registerTriggerCallback(baseAnycastTrigger->cl_trig, CL_CBK_TRIGGER_REFRESH_FAILED, dummy_trigger_refresh_failed, baseAnycastTrigger);

    context->registerContextCallback(CL_CBK_TRIGGER_NOT_FOUND, dummy_triggerNotFound, this);

    if (retCode != CL_RET_OK) {
        I3_PRINT_DEBUG0(I3_DEBUG_LEVEL_MINIMAL, "Unable to createTrigger!\n");
    }

   
    insertTrigger(baseAnycastTrigger, enableShortcut?CL_IFLAGS_TRIGGER_ALLOW_SHORTCUT:0);
    
}

/**
  * Generates a new anycast id from the baseAnycast id and puts it into id */
void I3OverlayNetwork::getNewLocalAnycastTriggerId (ID *id) {

    memcpy (id, &(baseAnycastTrigger->i3Id->id), sizeof (ID));
    memcpy ( ((unsigned char *) id->x + ID_LEN - sizeof (int) - 1), &nextAnycastIndex, sizeof (int));
    
    nextAnycastIndex++;

}

/**
  * Inserts the specified name keyed by the specified id.
  */
void I3OverlayNetwork::addNameById (ID *id, string name) {

    char tmpIdStr[MAX_PRINT_BUF];
    sprintf_i3_id (tmpIdStr, id);

    id_name_map.insert (pair<string, string>(tmpIdStr, name));
}

/**
  * Gets the name associated with the specified id.
  * If no name exists, the empty string "" is returned.
  */
string I3OverlayNetwork::getNameById (ID *id) {

    char tmpIdStr[MAX_PRINT_BUF];
    sprintf_i3_id (tmpIdStr, id);
   
    map<string, string>::iterator itr = id_name_map.find(tmpIdStr);
    
    if (itr != id_name_map.end()) {
        return itr->second;
        
    } else {
            
        return "";
    }
}

/**
  * Adds the mapping between the specified stack last id and
  * the given list of names.
  */
void I3OverlayNetwork::addMiddleBoxNamesById (string lastId, string nameList) {

    idStack_names_map.insert (pair<string, string>(lastId, nameList));
    
}

/**
  * Returns the comma separated list of names associated with the specified stack last id.
  */
string I3OverlayNetwork::getMiddleBoxNamesById (ID *id) {

    char tmpIdStr[MAX_PRINT_BUF];
    sprintf_i3_id (tmpIdStr, id);
    
    map<string, string>::iterator itr = idStack_names_map.find(tmpIdStr);
    
    if (itr != idStack_names_map.end()) {
        return itr->second;
        
    } else {
            
        return "";
    }
}


/** Destructor */
I3OverlayNetwork::~I3OverlayNetwork() {

#ifdef _WIN32
	if (updateStatusTimer != NULL) {
		updateStatusTimer->setDisabled();
	}
#endif
}

